﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace calendar
{
//参见mxl文件 Duration, 待..
public sealed class Duration : IComparable<Duration> , IEquatable<Duration>
{

    /**
    * Duration amount.
    */
    private double m_duration;

    /**
     * Duration type.
     */
    private TimeUnit m_units;

    private static readonly Duration[] ZERO_DURATIONS = {
        new Duration(0, TimeUnit.MINUTES),
        new Duration(0, TimeUnit.HOURS),
        new Duration(0, TimeUnit.DAYS),
        new Duration(0, TimeUnit.WEEKS),
        new Duration(0, TimeUnit.MONTHS),
        new Duration(0, TimeUnit.YEARS),
        new Duration(0, TimeUnit.PERCENT),
        new Duration(0, TimeUnit.ELAPSED_MINUTES),
        new Duration(0, TimeUnit.ELAPSED_HOURS),
        new Duration(0, TimeUnit.ELAPSED_DAYS),
        new Duration(0, TimeUnit.ELAPSED_WEEKS),
        new Duration(0, TimeUnit.ELAPSED_MONTHS),
        new Duration(0, TimeUnit.ELAPSED_YEARS),
        new Duration(0, TimeUnit.ELAPSED_PERCENT)
    };
    /**
    * Constructs an instance of this class from a duration amount and
    * time unit type.
    *
    * @param duration amount of duration
    * @param type time unit of duration
    */
    private Duration(double duration, TimeUnit type)
    {
        m_duration = duration;
        m_units = type;
    }

    private Duration(int duration, TimeUnit type)
    {
        m_duration = duration;
        m_units = type;
    }

    public double Value
    {
        get {
            return m_duration;
        }
    }

    public TimeUnit Units
    {
        get {
            return m_units;
        }
    }


    public static Duration getInstance(int value, TimeUnit type)
    {
        Duration result = null;
        if (value == 0) {
            result = ZERO_DURATIONS[type.Value];
        } else {
            result = new Duration(value, type);
        }
        return result;
    }

    public static Duration getInstance(double value, TimeUnit type)
    {
        Duration result = null;
        if (value == 0) {
            result = ZERO_DURATIONS[type.Value];
        } else {
            result = new Duration(value, type);
        }
        return result;
    }


    public Duration convertUnits(TimeUnit type, ProjectHeader defaults)
    {
        return (convertUnits(m_duration, m_units, type, defaults));
    }

    public Duration convertUnits(double duration, TimeUnit fromUnits, TimeUnit toUnits, ProjectHeader defaults)
    {
        return (convertUnits(duration, fromUnits, toUnits, defaults.MinutesPerDay, defaults.MinutesPerWeek, defaults.DaysPerMonth));

    }

    public Duration convertUnits(double duration, TimeUnit fromUnits, TimeUnit toUnits, double minutesPerDay, double minutesPerWeek, double daysPerMonth)
    {
        //throw new NotImplementedException();

        switch (fromUnits.Value) {
        case 6: { // YEARS
            duration *= (minutesPerWeek * 52);
            break;
        }

        case 12: { //ELAPSED_YEARS
            duration *= (60 * 24 * 7 * 52);
            break;
        }

        case 4: { //MONTHS
            duration *= (minutesPerWeek * 4);
            break;
        }

        case 11: { //ELAPSED_MONTHS
            duration *= (60 * 24 * 30);
            break;
        }

        case 3: { //WEEKS
            duration *= minutesPerWeek;
            break;
        }

        case 10: { //ELAPSED_WEEKS
            duration *= (60 * 24 * 7);
            break;
        }

        case 2: { //DAYS
            duration *= minutesPerDay;
            break;
        }

        case 9: { //ELAPSED_DAYS
            duration *= (60 * 24);
            break;
        }

        case 1: //HOURS
        case 8: { //ELAPSED_HOURS
            duration *= 60;
            break;
        }

        default: {
            break;
        }
        }

        if (toUnits != TimeUnit.MINUTES && toUnits != TimeUnit.ELAPSED_MINUTES) {
            switch (toUnits.Value) {
            case 1: //HOURS
            case 8: { //ELAPSED_HOURS
                duration /= 60;
                break;
            }

            case 2: { //DAYS
                if (minutesPerDay != 0) {
                    duration /= minutesPerDay;
                } else {
                    duration = 0;
                }
                break;
            }

            case 9: { //ELAPSED_DAYS
                duration /= (60 * 24);
                break;
            }

            case 3: { //WEEKS
                if (minutesPerWeek != 0) {
                    duration /= minutesPerWeek;
                } else {
                    duration = 0;
                }
                break;
            }

            case 10: { //ELAPSED_WEEKS
                duration /= (60 * 24 * 7);
                break;
            }

            case 4: { //MONTHS
                if (minutesPerWeek != 0) {
                    duration /= (minutesPerWeek * 4);
                } else {
                    duration = 0;
                }
                break;
            }

            case 11: { //ELAPSED_MONTHS
                duration /= (60 * 24 * 30);
                break;
            }

            case 6: { //YEARS
                if (minutesPerWeek != 0) {
                    duration /= (minutesPerWeek * 52);
                } else {
                    duration = 0;
                }
                break;
            }

            case 12: { //ELAPSED_YEARS
                duration /= (60 * 24 * 7 * 52);
                break;
            }

            default: {
                break;
            }
            }
        }
        return new Duration(duration, toUnits);
    }


    int IComparable<Duration>.CompareTo(Duration rhs)
    {
        if (m_units != rhs.m_units) {
            rhs = convertUnits(rhs.m_duration, rhs.m_units, m_units, (8 * 60), (5 * 8 * 60), 20);
        }

        return (m_duration < rhs.m_duration ? -1 : (m_duration == rhs.m_duration ? 0 : 1));
    }


    bool IEquatable<Duration>.Equals(Duration rhs)
    {
        bool result = false;
        result = (m_duration == rhs.m_duration && m_units == rhs.m_units);
        return result;
    }

    public override int GetHashCode()
    {
        return (m_units.Value + (int)m_duration);
    }

    public override string ToString()
    {
        return (m_duration + m_units.ToString());
    }
}
}
